package Features;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import core.Corpus;
import weka.core.tokenizers.NGramTokenizer;


public class Ngramas extends Feature{

	public HashMap<String, Integer> ngramList;
	public int maxNgramas = 100;
	
	public void iniciaMaxNgramas(String argumentos){
		if(argumentos.contains("ngramas=")){
			String temp = argumentos.split("ngramas=")[1];
			temp=temp.split(" ")[0];
			maxNgramas=Integer.parseInt(temp);
		}
	}
	
	public void imprimeListaNgramas(){
		Set<Map.Entry<String,Integer>> myNgramSet = ngramList.entrySet();
		Iterator<Map.Entry<String,Integer>> ngramIterator = myNgramSet.iterator();
		while(ngramIterator.hasNext()){
			Map.Entry<String,Integer> me = (Map.Entry<String,Integer>)ngramIterator.next();
			System.out.println(me.getKey());
		}
		System.out.println("Total de Ngramas = "+ ngramList.size());
	}
	
	public String carregaCorpus(Corpus corpus){
		
		String allSentences = new String();
		for(int i=0; i<corpus.listaDocumentos.length; i++){
			for(int j=0; j<corpus.listaDocumentos[i].sentenceList.length; j++){
				allSentences+=" "+corpus.listaDocumentos[i].sentenceList[j].frase;
			}
		}
		return allSentences;
	}
		
	//Funcao generica chamada pelas funcoes de treino de unigramas, bigramas e trigramas
	public void treinoNgramas(int N, String sentence){

		HashMap<String, Integer> ngramasMap = new HashMap<String, Integer>();
		NGramTokenizer ngrams = new NGramTokenizer();

		ngrams.setNGramMinSize(N);
		ngrams.setNGramMaxSize(N);
		ngrams.tokenize(sentence);
		while(ngrams.hasMoreElements()){
			String ngrama=(String) ngrams.nextElement();
			if(ngrama.codePointAt(0)==150 || ngrama.codePointAt(0)==151){ //patch
				continue;
			}
			if(ngramasMap.containsKey(ngrama)){
				int contador = (Integer) ngramasMap.get(ngrama);
				ngramasMap.put(ngrama, contador+1);
			}else{
				ngramasMap.put(ngrama, 1);
			}
		}
		ngramList = ngramasMap;
	}
	
	public String extractSentence(String sentence){
		String featureNgramas = new String();
		Set<Map.Entry<String,Integer>> myNgramSet = ngramList.entrySet();
		Iterator<Map.Entry<String,Integer>> ngramIterator = myNgramSet.iterator();
		while(ngramIterator.hasNext()){
			Map.Entry<String,Integer> me = (Map.Entry<String,Integer>)ngramIterator.next();
			if(sentence.contains(me.getKey())){
				featureNgramas+=" 1";
			}else{
				featureNgramas+=" 0";
			}
		}
		return featureNgramas;
	}
	
	/*public void extract(Document doc) throws Exception{
		if(activo==false) 
			return;
		for(int i=0; i<doc.sentenceList.length; i++){
			doc.sentenceList[i].featureVector+= extractSentence(doc.sentenceList[i].frase);
		}
	}*/
	
	public void filtraNgramas(){
		HashMap<String, Integer> map = ngramList;
		
		while(map.size()>maxNgramas){
			String maximo = minMaxMap(map);
			int valorMinimo = Integer.parseInt(maximo.split(";")[0]);
			int contadorMinimo = Integer.parseInt(maximo.split(";")[1]);
			int valorMaximo = Integer.parseInt(maximo.split(";")[2]);
			int contadorMaximo = Integer.parseInt(maximo.split(";")[3]);
			boolean max=false;

			if(map.size()-contadorMaximo>maxNgramas){
				map = removeValores(map, valorMaximo, valorMaximo, -1);
				//remove valor max do map
				max=true;
			}else{
				if(map.size()-contadorMinimo>maxNgramas){
					map = removeValores(map, valorMinimo, valorMinimo, -1);
					//remove valor min do map
					max=false;
				}else{
					map = removeValores(map, valorMinimo, valorMaximo, map.size()-maxNgramas);
					//caso especial -> remover max e min
				}
			}

			if(max){
				if(map.size()-contadorMinimo>maxNgramas){
					map = removeValores(map, valorMinimo, valorMinimo, -1);
					//remove valor minimo do map
				}else{
					map = removeValores(map, valorMinimo, valorMinimo, map.size()-maxNgramas);
					//caso especial -> remover alguns minimos
				}
			}

			if(!max){
				if(map.size()-contadorMaximo>maxNgramas){
					map = removeValores(map, valorMaximo, valorMaximo, -1);
					//remove valor maximo do map
				}else{
					map = removeValores(map, valorMaximo, valorMaximo, map.size()-maxNgramas);
					//caso especial -> remover alguns maximos
				}
			}
		}
		ngramList=map;
	}
	
	public String minMaxMap(HashMap<String, Integer> map){
		int minimo = 10000;
		int contadorMinimo = 0;
		int maximo = -1;
		int contadorMaximo = 0;

		ArrayList<Integer> valores = (ArrayList<Integer>) new ArrayList<Integer>(map.values());

		Iterator<Integer> it = valores.listIterator();
		int temp;
		while(it.hasNext()){
			temp = it.next();
			if(temp==minimo){
				contadorMinimo++;
			}else{
				if(temp<minimo){
					minimo=temp;
					contadorMinimo=1;
				}
			}
			if(temp==maximo){
				contadorMaximo++;
			}else{
				if(temp>maximo){
					maximo=temp;
					contadorMaximo=1;
				}
			}
		}		
		return minimo+";"+contadorMinimo+";"+maximo+";"+contadorMaximo;
	}

	public HashMap<String, Integer> removeValores(HashMap<String, Integer> NgramList, int A, int B, int limite){

		Set<Map.Entry<String,Integer>> myNgramSet = NgramList.entrySet();
		Iterator<Map.Entry<String,Integer>> NgramIterator = myNgramSet.iterator();
		HashMap<String, Integer> novaHash = new HashMap<String, Integer>();

		while(NgramIterator.hasNext() && limite!=0){	
			Map.Entry<String,Integer> me = (Map.Entry<String,Integer>)NgramIterator.next();
			if(me.getValue()==A || me.getValue()==B){
				limite--;
				continue;
			}
			novaHash.put(me.getKey(), me.getValue());
		}
		while(NgramIterator.hasNext()){
			Map.Entry<String,Integer> me = (Map.Entry<String,Integer>)NgramIterator.next();
			novaHash.put(me.getKey(), me.getValue());
		}

		return novaHash;
	}
	
}
